package com.yjzx.util.common.util.BeanUtils;

import com.yjzx.util.common.util.ExceptionUtil;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * @author yjzx
 * @date 2024/5/31
 * @description BaseInterface
 */
public interface BaseInterface<T> {
    default Optional<T> newGenericClassInstance() {
        return (Optional<T>) newGenericClassInstance(getGenericityClass());
    }

    default Optional<?> genericDefaultValue(Class<?> clazz) {
        if (clazz != null) {
            if (Map.class.equals(clazz) || AbstractMap.class.equals(clazz)) {
                return Optional.of(new HashMap<>());
            } else if (List.class.equals(clazz) || Collection.class.equals(clazz) || AbstractList.class.equals(clazz)) {
                return Optional.of(new ArrayList<>());
            } else if (Set.class.equals(clazz) || AbstractSet.class.equals(clazz)) {
                return Optional.of(new HashSet<>());
            }

        }
        return Optional.empty();
    }

    default Optional<?> newGenericClassInstance(Class<? super T> clazz) {
        Optional<?> optional = Optional.empty();
        try {
            Class<T> aClass = getGenericityClass();
            if (aClass.isInterface()) {
                optional = genericDefaultValue(clazz);
            } else if (clazz != null && !aClass.isAnnotation() && !aClass.isEnum()) {
                optional = Optional.of(aClass.newInstance());
            }
        } catch (InstantiationException | IllegalAccessException ignored) {

        }
        return optional;
    }

    default Class<T> getGenericityClass() {
        Type[] types = this.getClass().getGenericInterfaces();
        Type type = null;
        for (Type t : types) {
            if (t instanceof ParameterizedType && ((ParameterizedType) t).getRawType().getTypeName().equals(BaseInterface.class.getTypeName())) {
                type = t;
                break;
            }
        }
        if (type == null) {
            ExceptionUtil.throwException(RuntimeException.class, "无法获取当前类信息");
        }
        return (Class<T>) getGenericClass((ParameterizedType) type);
    }

    /**
     * 获取指定类的泛型类型
     *
     * @param paramType
     * @return
     */
    static Class<?> getGenericClass(ParameterizedType paramType) {
        //接口的的泛型
        Type[] arguments = paramType.getActualTypeArguments();
        for (Type type : arguments) {
            if (Class.class.isAssignableFrom(type.getClass())) {
                // T 无泛型获取
                return (Class<?>) type;
            } else if (ParameterizedType.class.isAssignableFrom(type.getClass())) {
                // T 有泛型获取
                ParameterizedType argument = (ParameterizedType) type;
                return (Class<?>) argument.getRawType();
            }
        }
        return null;
    }
}
